﻿using System.Collections.Generic;
using Deferred.Library;
using Deferred.Library.Scene;
using Deferred.Library.Scene.Visual;
using Deferred.Library.Scene.Graphics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Deferred.Library.Deferred
{
    class ForwardSceneRenderEngine : GraphicalComponent
    {
        private Effect drawEffect;
        private DeferredBase deferredBase;
        private EffectParameter worldParameter;

        public ForwardSceneRenderEngine(DeferredBase deferredBase)
            : base(deferredBase.DeviceService)
        {
            this.deferredBase = deferredBase;
        }

        public void Initialize()
        {
            drawEffect = deferredBase.Content.InternalContent.Load<Effect>("LinearDepth");
            drawEffect.CurrentTechnique = drawEffect.Techniques[0];

            worldParameter = drawEffect.Parameters["World"];
        }

        public void DrawObjects(IList<TerrainVisual> terrains, IList<DrawableObjectVisual> objects)
        {
            GraphicsDevice.RenderState.DepthBufferEnable = true;
            GraphicsDevice.RenderState.CullMode = CullMode.CullCounterClockwiseFace;
            GraphicsDevice.RenderState.AlphaBlendEnable = false;

            foreach (DrawableObjectVisual o in objects)
            {
                DrawObject(o);
            }
            foreach (TerrainVisual t in terrains)
            {
                DrawTerrain(t);
            }
        }

        private void DrawTerrain(TerrainVisual t)
        {
            worldParameter.SetValue(Matrix.CreateTranslation(t.Terrain.Position));
            GraphicsDevice.VertexDeclaration = t.VertexDeclaration;
            GraphicsDevice.Indices = t.IndexBuffer;
            GraphicsDevice.Vertices[0].SetSource(t.VertexBuffer, 0, TerrainVertex.SizeInBytes);
            drawEffect.Begin();
            foreach (EffectPass pass in drawEffect.CurrentTechnique.Passes)
            {
                pass.Begin();
                GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, t.VertexCount, 0, t.TriangleCount);
                pass.End();
            }
            drawEffect.End();
        }

        private void DrawObject(DrawableObjectVisual o)
        {
            worldParameter.SetValue(o.World);
            foreach (DeferredModelMesh mesh in o.Model.Meshes)
            {
                foreach (DeferredModelMeshPart part in mesh.MeshParts)
                {
                    GraphicsDevice.VertexDeclaration = part.VertexDeclaration;
                    GraphicsDevice.Vertices[0].SetSource(part.VertexBuffer, 0, part.VertexStride);
                    GraphicsDevice.Indices = part.IndexBuffer;
                    drawEffect.Begin();
                    foreach (EffectPass pass in drawEffect.CurrentTechnique.Passes)
                    {
                        pass.Begin();
                        GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, part.VertexCount, 0, part.TriangleCount);
                        pass.End();
                    }
                    drawEffect.End();
                }
            }
        }
    }
}
